package com.jonas.jgraph.inter;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.AttributeSet;

import com.jonas.jgraph.R;
import com.jonas.jgraph.graph.StateConstant;
import com.jonas.jgraph.graph.StyleAnnotation;
import com.jonas.jgraph.models.Jchart;
import com.jonas.jgraph.utils.CalloutHelper;
import com.jonas.jgraph.utils.MathHelper;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xujiang
 * @version 2017-08-03 09:15
 */
public class BaseGraphView extends BaseView {

    /**
     * 要画的 图表的 风格
     */
    protected int mGraphStyle = StateConstant.LINE;

    public int getGraphStyle() {
        return mGraphStyle;
    }

    /**
     * 是否允许 滚动
     */
    protected boolean mScrollAble = false;   // 是否允许滚动

    public boolean isScrollAble() {
        return mScrollAble;
    }

    public void setScrollAble(boolean scrollAble) {
        mScrollAble = scrollAble;
    }

    /**
     * 是否需要纵坐标
     */
    protected boolean mNeedY_abscissMasg = true;

    public boolean ismNeedY_abscissMasg() {
        return mNeedY_abscissMasg;
    }

    public void setNeedY_abscissMasg(boolean needY_abscissMasg) {
        mNeedY_abscissMasg = needY_abscissMasg;
    }

    /**
     * 柱状图 未选中选中的颜色
     */
    protected int mNormalColor = Color.DKGRAY;

    public int getNormalColor() {
        return mNormalColor;
    }

    public void setNormalColor(int normalColor) {
        mNormalColor = normalColor;
    }

    /**
     * 柱状图 选中的颜色
     */
    protected int mActivationColor = Color.RED;

    public int getActivationColor() {
        return mActivationColor;
    }

    public void setActivationColor(int activationColor) {
        mActivationColor = activationColor;
    }

    /**
     * 可见的 个数(柱状图(最多可见的柱子数量)/折线图(最多可见的点))
     * <p>可滚动的时候 mVisibleNums可以小于mchart的数量</p>
     * <p>不可滚动的时候 mVisibleNums必须大于等于mchart的数量</p>
     */
    protected int mVisibleNums = 0;

    public int getVisibleNums() {
        return mVisibleNums;
    }

    public void setVisibleNums(int visibleNums) {
        mVisibleNums = visibleNums;
    }

    /**
     * ==============================================================================================
     * 以上为xml 定义的属性
     * ==============================================================================================
     */

    protected Context mContext;

    /**
     * 图表显示的区域 x轴起点  左边为刻度
     * 图表显示区域 此区域除去padding，左边坐标文字宽度，下边坐标文字*2
     */
    protected RectF mChartArea;  //此处是可以画图表的区域，一个矩形对象

    /**
     * y轴最大的值
     */
    protected String mYaxismax = "100";

    /**
     * 选中模式 为-1 表示不处理点击选中状态
     */
    protected int mSelectedMode = -1;

    public void setSelectedMode(@StyleAnnotation.SelectedMode int selectedMode) {
        mSelectedMode = selectedMode;
    }

    protected float followingottom = 0;  // 线距离下面的距离

    public float getFollowingottom() {
        return followingottom;
    }

    public void setFollowingottom(float followingottom) {
        this.followingottom = followingottom;
    }

    /**
     * 画坐标文字信息
     */
    Paint horizontalAxisTextPaint;   // 画横纵坐标的画笔，计算区域需要

    public Paint getPaintAbsicssa() {  //得到绘制横纵坐标文字的Paint
        return horizontalAxisTextPaint;
    }

    /**
     * 横轴 文字大小
     */
    int horizontalAxisTextSize;    // 文字画笔字体大小

    float yMsgLength = 0;  //纵横坐标文字的宽度 按100计算
    float yMsgHeight = 0;  //选中点显示文字的背景高度 || 无背景效果时就是文字的高度

    /**
     * 虚线 用移动
     */
    protected float mPhase = 3;

    /**
     * 存放 纵轴信息
     */
    protected ArrayList<String> mYaxis_msg;  //一个值列表，记录着y轴的线的值
    protected float mYaxis_Max = 0;  // y轴的最大值
    protected float mYaxis_min;  //y轴的最小值

    public int showYnum = 3;  // 线的条数 （虚线条数加一为这个值）

    protected Paint mCoordinatePaint;  //画坐标轴  横轴

    public Paint getPaintCoordinate() {  //画 坐标轴  横轴
        return mCoordinatePaint;
    }

    /**
     * 虚线画笔
     */
    protected Paint mAbscisDashPaint;  //画虚线的画笔

    public Paint getmAbscisDashPaint() {
        return mAbscisDashPaint;
    }

    public void setmAbscisDashPaint(Paint mAbscisDashPaint) {
        this.mAbscisDashPaint = mAbscisDashPaint;
    }

    protected float mAbscisDashLineWidth = 0.5f;  // 虚线线宽

    float diffCoordinate;  //比例 将屏幕高度平分

    /**
     * 是否需要横轴信息
     */
    protected boolean showAbscissa = true;

    public boolean isShowAbscissa() {
        return showAbscissa;
    }

    public void setShowAbscissa(boolean showAbscissa) {
        this.showAbscissa = showAbscissa;
    }

    /**
     * @param xNums 几段
     * @param xinterval 每段多少
     */
    private int mXNums;
    private int mXinterval;

    /**
     * @param xNums 几段
     * @param xinterval 每段多少
     */
    public void setXnums(int xNums, int xinterval) {
        mXNums = xNums;
        mXinterval = xinterval;
    }

    public BaseGraphView(Context context) {
        this(context, null);
    }

    public BaseGraphView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseGraphView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AndroidJgraph);  //获取通过xml设置的属性值
        mGraphStyle = a.getInt(R.styleable.AndroidJgraph_graphstyle, StateConstant.LINE);
        mScrollAble = a.getBoolean(R.styleable.AndroidJgraph_scrollable, false);
        mNeedY_abscissMasg = a.getBoolean(R.styleable.AndroidJgraph_showymsg, true);
        mNormalColor = a.getColor(R.styleable.AndroidJgraph_normolcolor, Color.parseColor("#676567"));
        mActivationColor = a.getColor(R.styleable.AndroidJgraph_activationcolor, Color.RED);
        mVisibleNums = a.getInt(R.styleable.AndroidJgraph_visiblenums, 0);
        a.recycle();
        init(context);
    }

    private void init(Context context) {
        mContext = context;

        /**
         * 横坐标的文字
         */
        horizontalAxisTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  //抗锯齿
        horizontalAxisTextPaint.setTextAlign(Paint.Align.CENTER);  //文本居中
        horizontalAxisTextSize = MathHelper.dip2px(mContext, 12);  //12个dip大小
        horizontalAxisTextPaint.setTextSize(horizontalAxisTextSize);  //设置文字大小
        horizontalAxisTextPaint.setColor(
                ContextCompat.getColor(context, R.color.coordinates_text));  //设置文字颜色  //Color.parseColor("#556A73")
        /**
         * 横轴初始化
         */
        mCoordinatePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCoordinatePaint.setStyle(Paint.Style.STROKE);  //让画出的图形是空心的
        mCoordinatePaint.setColor(ContextCompat.getColor(context, R.color.white));  //设置颜色
        mCoordinatePaint.setStrokeWidth(2f);  //设置笔画的宽度

        /**
         * 虚线初始化设置
         */
        mAbscisDashPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mAbscisDashPaint.setStrokeWidth(mAbscisDashLineWidth);  // 0.5f宽度
        mAbscisDashPaint.setStyle(Paint.Style.STROKE);  //空心
        mAbscisDashPaint.setColor(ContextCompat.getColor(context, R.color.white));  //虚线颜色

    }

    //onMeasure()→onSizeChanged()→onLayout()→onMeasure()→onLayout()→onDraw()
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        initChartArea();  // onSizeChanged 会在构造函数后面调用  所以不能在构造函数里初始化（这是必须的  不然虚线会出错）
        diffCoordinate = mChartArea.height() / (showYnum - 1);  //(这个也是)
    }

    /**
     * 此函数用于确定可以画图的区域,在画布上圈定一个区域画图 将轴信息的位置空余出来
     */
    public void initChartArea() {

        Rect bounds = new Rect();  // 用于得到横轴文字的大小

        //计算文字所在矩形，可以得到宽高
        horizontalAxisTextPaint.getTextBounds(mYaxismax, 0, mYaxismax.length(), bounds);
        yMsgLength = horizontalAxisTextPaint.measureText(mYaxismax, 0, mYaxismax.length());

        if (mNeedY_abscissMasg) {
            //如果 需要 纵轴坐标的时候
            // 粗略计算文字宽度
            if (mYaxis_msg != null && mYaxis_msg.size() >= 0) {  // 防止 mYaxis_msg 空指针错误
                for (String mYaxi : mYaxis_msg) {  // 计算y轴最长的数据长度
                    float leng = horizontalAxisTextPaint.measureText(mYaxi, 0, mYaxi.length());
                    yMsgLength = yMsgLength > leng ? yMsgLength : leng;
                }
            }
            //yMsgLength = bounds.width() < yMsgLength ? bounds.width() : yMsgLength;
            yMsgLength += 5; //多5像素 //http://blog.csdn.net/lyndsc/article/details/51556508
        }

        if (mSelectedMode == StateConstant.SELECETD_MSG_SHOW_TOP) { //有背景效果
            //选中文字的背景的高度
            //            yMsgHeight = mSelectedTextPaint.getTextSize()+3f*mBgTriangleHeight;
            yMsgHeight = CalloutHelper.getCalloutHeight();
        } else {  //否则
            yMsgHeight = bounds.height();  // 就是文字的高度
        }
        //float left, float top, float right, float bottom
        //更改显示效果在此处
        followingottom = 2 * horizontalAxisTextSize;  // 两个文字高度
        //TODO  这里规定了图表的显示区域及周边空余
        mChartArea = new RectF(yMsgLength + getPaddingLeft(), getPaddingTop() + yMsgHeight, mWidth + getPaddingLeft(),
                getPaddingTop() + mHeight - followingottom);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawCoordinateAxes(canvas, mCoordinatePaint, 0);  // 画横线
        drawDottedLine(canvas, mChartArea.right);  // 画虚线

    }

    /**
     * 画虚线
     */
    public void drawDottedLine(Canvas canvas, float ydash_x) {
        if (mYaxis_msg != null && mYaxis_msg.size() >= 2) {
            for (int i = 0; i < mYaxis_msg.size(); i++) {
                float levelCoordinate = mChartArea.bottom - diffCoordinate * i;  //底部坐标 - 每个的间隔
                if (i > 0) {
                    drawDottedLine(levelCoordinate, ydash_x, mAbscisDashPaint, canvas);
                }
            }
        }
        mPhase = ++mPhase % 50;  //使虚线有滚动效果
    }

    /**
     * 画 坐标轴  横轴
     *
     * @param canvas 画布对象
     * @param mCoordinatePaint 画横线的画笔
     * @param coordinate_x 如果滚动 x轴结束的位置坐标
     */
    protected void drawCoordinateAxes(Canvas canvas, Paint mCoordinatePaint, float coordinate_x) {
        if (mScrollAble) {  //可以滚动
            //float coordinate_x = mChartRithtest_x + mBarWidth / 2;
            coordinate_x = coordinate_x < mChartArea.right ? mChartArea.right : coordinate_x;
            // ToDo 画横线
            canvas.drawLine(mChartArea.left, mChartArea.bottom, coordinate_x, mChartArea.bottom, mCoordinatePaint);
        } else {  //不可滚动
            canvas.drawLine(mChartArea.left, mChartArea.bottom, mChartArea.right, mChartArea.bottom, mCoordinatePaint);
        }
    }

    /**
     * 画虚线
     *
     * @param levelCoordinate 虚线开始的y坐标
     * @param ydash_x 虚线结束的x坐标
     * @param mAbscisDashPaint 画笔
     * @param canvas 画布
     */
    public void drawDottedLine(float levelCoordinate, float ydash_x, Paint mAbscisDashPaint, Canvas canvas) {
        Path dashPath = new Path();  //虚线的path
        dashPath.moveTo(mChartArea.left, levelCoordinate);    //mChartArea图表显示的区域 x轴起点  左边为刻度
        dashPath.lineTo(ydash_x, levelCoordinate);
        mAbscisDashPaint.setPathEffect(pathDashEffect(new float[] { 4, 4 }));  //4像素实线 4像素空白
        // ToDo 画虚线在这里画的
        canvas.drawPath(dashPath, mAbscisDashPaint);
    }

    /**
     * 虚线设置效果
     */
    protected DashPathEffect pathDashEffect(float[] intervals) {                     //线，段，线，段
        /**
         *DashPathEffect是PathEffect类的一个子类,可以使paint画出类似虚线的样子,并且可以任意指定虚实的排列方式。

         举个例子：
         Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
         p.setStyle(Style.STROKE);
         p.setColor(Color.WHITE);
         p.setStrokeWidth(1);
         PathEffect effects = new DashPathEffect(new float[] { 1, 2, 4, 8}, 1);
         p.setPathEffect(effects);
         canvas.drawLine(0, 40, mWidth, 40, p);
         代码中的float数组,必须是偶数长度,且>=2,指定了多少长度的实线之后再画多少长度的空白。

         如本代码中,绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白,依次重复。1是起始位置的偏移量。

         */
        DashPathEffect dashEffect = new DashPathEffect(intervals, mPhase);  //偏移3个单位
        return dashEffect;
    }

    /**
     * 刷新Y轴值
     */
    public void refreshYaxisValues() {

        mYaxis_msg = new ArrayList<>(showYnum);
        float diffLevel = (mYaxis_Max - mYaxis_min) / ((float) showYnum - 1);  //y轴值间距
        for (int i = 0; i < showYnum; i++) {
            mYaxis_msg.add(new DecimalFormat("#").format(mYaxis_min + diffLevel * i));
        }
    }

    /**
     * 设置y轴 刻度 信息
     * <p>所有数据设置为0 （showYnum为0）则会根据数据自动计算y轴需要显示的最大值最小值为0
     *
     * @param min y轴 显示的最小值
     * @param max y轴显示的最大值
     */
    public void setYaxisMinMaxValues(int min, int max) {
        mYaxis_Max = max;
        mYaxis_min = min;
        refreshYaxisValues();  // 更新数组里的值
    }

    /**
     * 设置y轴 刻度 信息
     *
     * @param showMsg y轴显示 内容
     */
    public void setYaxisValues(@NonNull List<String> showMsg) {
        mYaxis_msg = new ArrayList<>(showMsg.size());
        for (int i = 0; i < showMsg.size(); i++) {
            mYaxis_msg.add(showMsg.get(i));
        }
        showYnum = mYaxis_msg.size();
        if (mChartArea != null) {
            diffCoordinate = mChartArea.height() / (showYnum - 1);
        }

    }

    /**
     * 画纵坐标信息和虚线
     */
    protected void drawYabscissaMsg(Canvas canvas, List<Jchart> mJcharts, float mChartRithtest_x, float mBarWidth) {
        //文字左对齐
        horizontalAxisTextPaint.setTextAlign(Paint.Align.LEFT);
        for (int i = 0; i < mYaxis_msg.size(); i++) {
            float levelCoordinate = mChartArea.bottom - diffCoordinate * i;  //底部坐标 - 每个的间隔
            if (mNeedY_abscissMasg) {  // 允许画y州值
                // ToDo 画Y轴的text 信息
                canvas.drawText(mYaxis_msg.get(i), getPaddingLeft(), levelCoordinate, horizontalAxisTextPaint);
            }
            if (i > 0) {
                float ydash_x;
                if (mJcharts != null && mJcharts.size() > 0) {
                    ydash_x = mChartRithtest_x < mChartArea.right ? mChartArea.right : mChartRithtest_x + mBarWidth / 2;
                } else {
                    ydash_x = mChartArea.right;
                }
                // 画虚线
                drawDottedLine(canvas, ydash_x);

            }
        }
    }

    /**
     * 画 对应的 横轴信息  横轴文字
     */
    protected void drawAbscissaMsg(Canvas canvas, Jchart excel) {
        if (showAbscissa) {
            if (mXinterval != 0 && mXNums != 0) {  //如果设置了段
                drawAbscissaMsg(canvas);  //不知道他在干什么
            } else {
                horizontalAxisTextPaint.setTextAlign(Paint.Align.CENTER);  //设置画笔开始模式
                float mWidth = this.mWidth + getPaddingLeft() + getPaddingRight();  //控件的全部宽度
                if (null != excel) {
                    PointF midPointF = excel.getMidPointF();  // 数据中间点坐标
                    if (!TextUtils.isEmpty(excel.getXmsg())) {  //横坐标信息
                        String xmsg = excel.getXmsg();
                        float w = horizontalAxisTextPaint.measureText(xmsg, 0, xmsg.length());  // 横坐标文字宽度
                        /**
                         * 不滚动时画文字
                         */
                        if (!mScrollAble) {  // 当不可滚动时
                            if (midPointF.x - w / 2 < 0) { // 如果中点x轴 减去 文字宽度的一半小于 0 及超出了坐标系左边
                                //最左边
                                // ToDO x 轴 左边第一个文字画文字
                                canvas.drawText(excel.getXmsg(), w / 2,
                                        mChartArea.bottom + MathHelper.dip2px(mContext, 3) + horizontalAxisTextSize,
                                        horizontalAxisTextPaint);
                            } else if (midPointF.x + w / 2 > mWidth) {  //如果超出右边
                                //最右边
                                canvas.drawText(excel.getXmsg(), mWidth - w / 2,
                                        mChartArea.bottom + MathHelper.dip2px(mContext, 3) + horizontalAxisTextSize,
                                        horizontalAxisTextPaint);
                            } else {        //在中间时
                                canvas.drawText(excel.getXmsg(), midPointF.x,
                                        mChartArea.bottom + MathHelper.dip2px(mContext, 3) + horizontalAxisTextSize,
                                        horizontalAxisTextPaint);
                            }
                        } else {  //如果滚动  直接取中间的坐标
                            canvas.drawText(excel.getXmsg(), midPointF.x,
                                    mChartArea.bottom + MathHelper.dip2px(mContext, 3) + horizontalAxisTextSize,
                                    horizontalAxisTextPaint);
                        }
                    }
                }
            }
        }

    }

    /**
     * 设置了段的横轴信息在这了画（显然这里没被调用）
     */
    private void drawAbscissaMsg(Canvas canvas) {
        int mTotalTime = mXinterval * mXNums;  //合计总数
        String total = String.valueOf(mTotalTime);
        float xWi = mWidth - mChartArea.left - getPaddingRight() - horizontalAxisTextPaint.measureText(total, 0,
                total.length());
        for (int i = 0; i < mXNums + 1; i++) {
            String xmsg = String.valueOf(mXinterval * i);
            float w = horizontalAxisTextPaint.measureText(xmsg, 0, xmsg.length());
            float textX = mChartArea.left + mXinterval * i / mTotalTime * xWi;
            if (textX + w / 2 > mWidth) {
                textX = mWidth - w;
            }
            canvas.drawText(xmsg, textX, mChartArea.bottom + MathHelper.sp2px(mContext, 3) + horizontalAxisTextSize,
                    horizontalAxisTextPaint);
        }
    }

}
